package afcp.alumni.dao.base;

import java.util.List;

import net.sf.jsr107cache.CacheException;
import afcp.alumni.action.base.MyActionBeanContext;
import afcp.alumni.model.SearchResult;
import afcp.alumni.model.base.DatastoreEntity;
import afcp.alumni.model.base.MyEntity;
import afcp.alumni.util.Conf;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

//@Deprecated
public interface Dao<T extends MyEntity> {
	
	public DatastoreEntity getEntityAncestor();

	/**
	 * Returns a list of all the entities of this kind (<em>T</em>) in the
	 * datastore.
	 * 
	 * @return All the entities of kind <em>T</em> in datastore.
	 */
	public List<T> findAll();

	public SearchResult<T> findOnePage(int page, int perPage);

	/**
	 * <p>
	 * Find and return the entity with the given id.
	 * </p>
	 * <p>
	 * If the Key was generated automatically, it might be from a long instead
	 * of a String, and this method would not find the entity.
	 * </p>
	 * <p>
	 * Warning: The returned entity is detached. For instance, it can't be used
	 * to remove it from the datastore.
	 * </p>
	 * 
	 * @param id
	 * @return the entity found or null if not found.
	 */
	public T find(String id);

	public SearchResult<T> find(List<String> ids,
			int page, int perPage);
	
	public SearchResult<T> find(List<String> ids,
			int page, int perPage, long totalResults);

	public T findFromKeyString(String key);

//	/**
//	 * <p>
//	 * Find and return the entity with the unique field.
//	 * </p>
//	 * <p>
//	 * Warning: The returned entity is detached. For instance, it can't be used
//	 * to remove it from the datastore.
//	 * </p>
//	 * 
//	 * @param id
//	 * @return
//	 */
//	public <U extends WithUniqueField> U find(UniqueField<U> field);

	/**
	 * App Engine note: the performances are bad with the current implementation
	 * <code>query.setFilter(":p.contains(key)");</code> - one query for each
	 * key. Please avoid using this method if possible.
	 * 
	 * @param ids
	 * @param page
	 * @param perPage
	 * @return
	 */
	public SearchResult<T> findFromKeyStrings(List<String> ids,
			int page, int perPage);
	
//	public abstract List<T> findFromKeyString(List<T> keys);

	/**
	 * App Engine note: the performances are bad with the current implementation
	 * <code>query.setFilter(":p.contains(key)");</code> - one query for each
	 * key. Please avoid using this method if possible.
	 * 
	 * @param ids
	 * @param page
	 * @param perPage
	 * @param totalResults
	 *            if the total number of results is already known. If not, you
	 *            may prefer to use {@link #findFromKeyStrings(List, int, int)}
	 * @return
	 */
	public SearchResult<T> findFromKeyStrings(List<String> ids,
			int page, int perPage, long totalResults);
	
	/**
	 * An implementation represents a processing of members.
	 * @author aorylamballe
	 *
	 * @param <U>
	 */
	public static interface MemberProcessor<U> {
		public boolean process(List<U> membersOfOnePage);
	}

	/**
	 * {@link MemberProcessor#process(List)} is called as many times as members
	 * are found in datastore. Each time, a buffer of members is retrieved, of
	 * size {@link Conf#BUFFER_SIZE}.
	 * 
	 * @param memberProcessor
	 *            an implementation of {@link MemberProcessor} specifying which
	 *            processing is done for each set of members retrieved from
	 *            datastore.
	 * @return true on success, false if one of the processings returned false.
	 */
	public boolean processAllMembers(MemberProcessor<T> memberProcessor);

	public boolean exists(T entity);

	public SearchResult<T> search(String queryString, int page, int perPage);

	/**
	 * Adds the given entity to the datastore. Its Id must be set and not be
	 * already used in the datastore. If the id is already used, an error log is
	 * writen.
	 * 
	 * @param entity
	 *            The entity to add to the datastore.
	 * @return True if the entity was successfully added to the datastore, false
	 *         otherwise.
	 */
	public boolean addOrUpdate(T entity);
	
	public boolean updateNoReindexingNoValidation(T entity);

	public boolean addOrUpdate(T entity, boolean indexes);

	public boolean addToIndex(T entity);

	public boolean addOrUpdate(List<T> entities);

	public boolean addOrUpdate(List<T> entities, boolean detach);

	public boolean addToIndex(List<T> entities);

	/**
	 * Removes the entity with the given id in the string form.
	 * 
	 * @param id
	 *            The id of the entity to delete. The method
	 *            {@link KeyFactory#stringToKey(String)} is used to find the key
	 *            from this String. It means that this id must have been
	 *            generated using the method {@link KeyFactory#keyToString(Key)}
	 *            .
	 * @return
	 */
	public T removeFromKeyString(String id);

	/**
	 * Removes the entity with the given key String ({@link String} form of its
	 * {@link Key}) from the index. To get a String from a Key, you may want to
	 * use {@link KeyFactory#keyToString(Key)}.
	 * 
	 * @param key
	 * @return
	 */
	public boolean removeFromIndex(String key);
	
	public void remove(T entity);

	/**
	 * Removes the entity with the given id which is the {@link String} form of
	 * the <code>long</code> key id. To get a {@link String} id from a
	 * {@link Key}, you may want to use {@link Key#getName()}. To convert a long
	 * to a string id, you may want to create a key with
	 * {@link KeyFactory#createKey(String, long)} and then get the String id.
	 * 
	 * @param id
	 *            The {@link String} form of the id. Use the {@link KeyFactory}
	 *            and the {@link Key} objects to convert the key id from long to
	 *            {@link String}.
	 * @return
	 */
	public T remove(String id);

	public boolean remove(List<T> entities);

	public boolean removeFromIndex(List<String> ids);

	public boolean removeAll();

	public boolean removeAllFromIndex();

	public boolean clearIndex();

	/**
	 * Updates an entity still attached to the datastore.
	 * 
	 * @param entity
	 *            The entity to update in the datastore
	 * @return
	 */
	public boolean update(T entity);
	
	public void clearSessions();
	
	public void clearCache() throws CacheException;
	
	public static class KindInfo {
		private String kindName;
		private long count;
		private long bytes;
		public KindInfo(String kindName, long count, long bytes) {
			super();
			this.kindName = kindName;
			this.count = count;
			this.bytes = bytes;
		}
		public String getKindName() {
			return kindName;
		}
		public void setKindName(String kindName) {
			this.kindName = kindName;
		}
		public long getCount() {
			return count;
		}
		public void setCount(long count) {
			this.count = count;
		}
		public long getBytes() {
			return bytes;
		}
		public void setBytes(long bytes) {
			this.bytes = bytes;
		}
	}
	
	public List<KindInfo> listKindsWithStats();
	
	public List<KindInfo> listKinds();
	
	public boolean removeByKindName(String kindName);
	
	public boolean clearAllDatastore(MyActionBeanContext context);

	// public abstract long getTotalResults();

//	/**
//	 * <p>
//	 * Get the object that can be used to do a transaction. Call then
//	 * {@link Transaction#begin()} to start the transaction,
//	 * {@link Transaction#commit()} to commit (end) the transaction and
//	 * {@link Transaction#rollback()} to rollback on finally block if
//	 * transaction is active ({@link Transaction#isActive()}).
//	 * </p>
//	 * <p>
//	 * Transactions are subject to restrictions on datastore (ie they might
//	 * throw {@link Exception}s) and might affect concurrency. So be careful
//	 * when using it.
//	 * </p>
//	 * 
//	 * @return The {@link Transaction} object that will be used to call
//	 *         {@link Transaction#begin()}, {@link Transaction#commit()},
//	 *         {@link Transaction#isActive()} and {@link Transaction#rollback()}
//	 *         methods.
//	 */
//	public Transaction newTransactionObject();
//
//	public void beginTransaction(Transaction txn);
//
//	public void commitTransaction(Transaction txn);
//
//	public void rollbackTransaction(Transaction txn);

}
